package com.webServer.http;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static com.webServer.utils.ParseString.send;

/**
 * @Auther:SYZ
 * @Date:2022/8/2 - 08 - 02 - 13:34
 * @Description:
 *       响应对象,将请求的数据响应给客户端
 *       响应对象有三个组成:
 *          1.状态行
 *          2.响应头
 *          3.响应正文
 * @version:1.0
 */
public class HttpServletResponse {
    private Socket socket;
    private int stateCode = 200;
    private String stateReason = "ok";
    private Map<String,String> headers = new HashMap<>();
    private File contentFile;
    private ByteArrayOutputStream baos;
    private byte[] contentData;//作为响应正文数据的字节数组

    public HttpServletResponse(Socket socket) {
        this.socket = socket;
    }
    public void response() throws IOException {
        //1.发送前的准备工作
        sendBefore();
        //2.发送状态行
        sendStateLine();
        //3.发送响应头
        sendHeaders();
        //4.发送响应正文
        sendContent();
    }
    //发送前准备工作
    private void sendBefore(){
        //判断baos是否为null
        if(baos!=null){
            //得到其内部的字节数组(动态数据)
            contentData = baos.toByteArray();
        }
        //如果动态数据数组不为null,添加响应头Content-Length
        if(contentData!=null){
            addHeader("Content-Length",contentData.length+"");
        }
    }

    /***
     * 发送状态行
     */
    private void sendStateLine() throws IOException {
        send("HTTP/1.1 "+stateCode+" "+stateReason,socket);
    }

    /***
     * 发送响应头
     */
    private void sendHeaders() throws IOException {
        Set<Map.Entry<String, String>> entrySet = headers.entrySet();
        for (Map.Entry<String, String> e : entrySet) {
            String key = e.getKey();
            String value = e.getValue();
            send(key+": "+value,socket);
        }
        //单独发送回车换行表示响应头发送完毕了
        send("",socket);
    }

    /***
     * 发送响应正文
     * @throws IOException
     */
    private void sendContent() throws IOException {
        if(contentData!=null){
            OutputStream out = socket.getOutputStream();
            out.write(contentData);
        }else if(contentFile!=null){
            OutputStream out = socket.getOutputStream();
            FileInputStream fis = new FileInputStream(contentFile);
            int len;
            byte[] data = new byte[1024 * 10];
            while ((len = fis.read(data))!=-1){
                out.write(data,0,len);
            }
        }
    }

    public int getStateCode() {
        return stateCode;
    }

    public void setStateCode(int stateCode) {
        this.stateCode = stateCode;
    }

    public String getStateReason() {
        return stateReason;
    }

    public void setStateReason(String stateReason) {
        this.stateReason = stateReason;
    }

    public File getContentFile() {
        return contentFile;
    }

    public void setContentFile(File contentFile) {
        this.contentFile = contentFile;
        String contentType = null;
        try {
            contentType = Files.probeContentType(contentFile.toPath());
        } catch (IOException e) {
            e.printStackTrace();
        }
        /*
            当我们无法根据正文文件确定类型时，则不发送Content-Type
            在HTTP协议中当响应包含正文，但是不包含Content-Type时，则表示让浏览器
            自行判断响应正文内容
         */
        if(contentType!=null) {
            addHeader("Content-Type", contentType);
        }
        addHeader("Content-Length",contentFile.length()+"");
    }
    public void addHeader(String s, String s1) {
        headers.put(s,s1);
    }
    /**
     * 返回一个字节输出流，通过这个流写出的数据最终会作为响应正文内容发送给浏览器
     * 只要响应对象相同，无论调用多少次该方法，返回的始终是同一个输出流。
     * @return
     */
    public OutputStream getOutputStream(){
        if(baos==null){
            baos = new ByteArrayOutputStream();
        }
        return baos;
    }

    /**
     * 通过该方法获取的缓冲字符输出流写出的文本会作为正文内容发送给浏览器
     * @return
     */
    public PrintWriter getWriter(){
        return new PrintWriter(
                new BufferedWriter(
                        new OutputStreamWriter(
                                getOutputStream(),
                                StandardCharsets.UTF_8
                        )
                ),true
        );
    }

    /**
     * 设置响应头Content-Type的值
     * @param mime
     */
    public void setContentType(String mime){
        addHeader("Content-Type",mime);
    }

    /**
     * 使浏览器重定向到指定位置
     * @param location
     */
    public void sendRedirect(String location){
        /*
            重定向的规则:
            响应中的状态代码为302
            响应头中应当包含Location
            没有响应正文
         */
        this.stateCode = 302;
        this.stateReason = "Moved Temporarily";

        addHeader("Location",location);

    }
}
